package com.icoo.apigateway.config;

import cn.dev33.satoken.stp.StpUtil;
import com.icoo.base.enums.CustomerEnum;
import com.icoo.base.targets.InterceptAnnotation;
import com.icoo.base.utils.ReflectHelper;
import io.netty.util.internal.StringUtil;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;

/***
 * mybatisPlus sql拦截器
 */

@Component
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class MybatisPlusInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (invocation.getTarget() instanceof RoutingStatementHandler) {

            RoutingStatementHandler statementHandler = (RoutingStatementHandler) invocation
                    .getTarget();
            StatementHandler delegate = (StatementHandler) ReflectHelper
                    .getFieldValue(statementHandler, "delegate");
            BoundSql boundSql = delegate.getBoundSql();
            Object obj = boundSql.getParameterObject();

            // 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
            MappedStatement mappedStatement = (MappedStatement) ReflectHelper
                    .getFieldValue(delegate, "mappedStatement");

            // 拦截到的prepare方法参数是一个Connection对象
            Connection connection = (Connection) invocation.getArgs()[0];
            // 获取当前要执行的Sql语句，也就是我们直接在Mapper映射语句中写的Sql语句
            String sql = boundSql.getSql();
            String msql = sql;
            Class<?> classType = Class.forName(mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf(".")));
            String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1);
            for (Method method : classType.getMethods()) {
                if (method.isAnnotationPresent(InterceptAnnotation.class) && mName.equals(method.getName())) {
                    InterceptAnnotation interceptorAnnotation = method.getAnnotation(InterceptAnnotation.class);
                    if (interceptorAnnotation.flag()) {
                        //获取当前用户所属逻辑库
                        String customer = (String) StpUtil.getSession().get(CustomerEnum.CUSTOMER);
                        if(StringUtil.isNullOrEmpty(customer))
                            throw new Exception("用户未登陆，获取不到用户所属逻辑库！");
                        msql = "/*mycat:schema="+ customer +"*/" + sql;
                    }
                }
            }
            ReflectHelper.setFieldValue(boundSql, "sql", msql);
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
